跳到主要内容

JZ63 数据流中的中位数

https://www.nowcoder.com/practice/9be0172896bd43948f8a32fb954e1be1

注意:PriorityQueue 默认是从小到大排序

这一题主要的思想是利用优先队列,优先队列分为大顶堆和小顶堆,默认维护的是小顶堆的优先队列。

需要求的是中位数,如果我将 1 2 3 4 5 6 7 8定为最终的数据流 此时的中位数是 4 + 5 求均值。为什么是 4,为什么是 5 利用队列我们就可以看得很清楚,4 是前半部分最大的值,肯定是维系在大顶堆 而 5 是后半部分的最小值,肯定是维系在小顶堆。

问题就好理解了: 使用小顶堆存大数据,使用大顶堆存小数据。这样堆顶一取出就是中位数了。

import java.util.*;
 
public class Solution {
    // 代表排序后的左半部分 // 5 6 7 8
    private PriorityQueue<Integer> maxHeap = new PriorityQueue<>((o1, o2) -> o2 - o1);
    // 代表排序后的右半部分 // 4 3 2 1
    private PriorityQueue<Integer> minHeap = new PriorityQueue<>();
 
    // 时间复杂度O(logn)
    public void Insert(Integer num) {
        // 平均分配,元素个数为奇数时插入到maxHeap,为偶数时插入到minHeap
        if ((minHeap.size() + maxHeap.size()) % 2 == 1) {
            // 若num完全小于minHeap的所有元素,直接将num插入maxHeap即可
            // 若num大于minHeap中的一些元素,则将num插入minHeap, 然后移除minHeap的最小值,将其插入maxHeap
            if (!minHeap.isEmpty() && num > minHeap.element()) {
                minHeap.add(num);
                num = minHeap.remove();
            }
            maxHeap.add(num);
        } else {
            // 若num完全大于maxHeap的所有元素,直接将num插入minHeap即可
            // 若num小于maxHeap中的一些元素,则将num插入maxHeap,然后移除maxHeap的最大值,将其插入minHeap
            if (!maxHeap.isEmpty() && num < maxHeap.element()) {
                maxHeap.add(num);
                num = maxHeap.remove();
            }
            minHeap.add(num);
        }
    }
 
    // 时间复杂度O(1)
    public Double GetMedian() {
        int size = maxHeap.size() + minHeap.size();
        if (size % 2 == 1) {
            return minHeap.element() * 1.0;
        } else {
            return (maxHeap.element() + minHeap.element()) / 2.0;
        }
    }
 
}